home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume10 / agetty2 < prev    next >
Encoding:
Text File  |  1990-01-28  |  30.5 KB  |  1,051 lines

  1. Newsgroups: comp.sources.misc
  2. organization: Eindhoven University of Technology, The Netherlands
  3. keywords: agetty2
  4. subject: v10i050: agetty, SYSV getty for dial-in lines
  5. from: wietse@wzv.win.tue.nl (Wietse Z. Venema)
  6. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  7.  
  8. Posting-number: Volume 10, Issue 50
  9. Submitted-by: wietse@wzv.win.tue.nl (Wietse Z. Venema)
  10. Archive-name: agetty2
  11.  
  12. This is a SYSV getty replacement with useful features for dial-in lines.
  13.  
  14. The program adjusts the tty modes to parity bits, and to erase, kill and
  15. end-of-line characters found while reading a login name.  The baud rate
  16. of incoming calls can be established by BREAK character processing or by
  17. parsing status messages produced by multi-speed Hayes-compatible modems.
  18.  
  19. The first release of this program appeared december 1989. The main new 
  20. feature introduced here is selective processing of the /etc/issue file.
  21.  
  22. #! /bin/sh
  23. # This is a shell archive.  Remove anything before this line, then unpack
  24. # it by saving it into a file and typing "sh file".  To overwrite existing
  25. # files, type "sh file -c".  You can also feed this as standard input via
  26. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  27. # will see the following message at the end:
  28. #        "End of shell archive."
  29. # Contents:  README agetty.c agetty.8 Makefile
  30. # Wrapped by wietse@wzv on Sun Jan 28 17:56:42 1990
  31. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  32. if test -f 'README' -a "${1}" != "-c" ; then 
  33.   echo shar: Will not clobber existing file \"'README'\"
  34. else
  35. echo shar: Extracting \"'README'\" \(440 characters\)
  36. sed "s/^X//" >'README' <<'END_OF_FILE'
  37. X@(#) README 1.4 1/28/90 17:53:02
  38. X
  39. XThis is a SYSV getty replacement with useful features for dial-in lines.
  40. X
  41. XThe program adjusts the tty modes to parity bits, and to erase, kill and
  42. Xend-of-line characters found while reading a login name.  The baud rate
  43. Xof incoming calls can be established by BREAK character processing or by
  44. Xparsing status messages produced by multi-speed Hayes-compatible modems.
  45. X
  46. X        Wietse Venema (wietse@wzv.win.tue.nl)
  47. END_OF_FILE
  48. if test 440 -ne `wc -c <'README'`; then
  49.     echo shar: \"'README'\" unpacked with wrong size!
  50. fi
  51. # end of 'README'
  52. fi
  53. if test -f 'agetty.c' -a "${1}" != "-c" ; then 
  54.   echo shar: Will not clobber existing file \"'agetty.c'\"
  55. else
  56. echo shar: Extracting \"'agetty.c'\" \(22691 characters\)
  57. sed "s/^X//" >'agetty.c' <<'END_OF_FILE'
  58. X/*++
  59. X/* NAME
  60. X/*    agetty 8
  61. X/* SUMMARY
  62. X/*    alternative System-V getty for dial-up lines
  63. X/* SYNOPSIS
  64. X/*    agetty [-a alternate_rates] [-h] [-i] [-m] [-t timeout] port baud_rate
  65. X/* DESCRIPTION
  66. X/*    \fIagetty\fR opens a tty port, prompts for a login name and invokes the
  67. X/*    /bin/login command. It is normally invoked by \fIinit(8)\fR.
  68. X/*
  69. X/*    \fIagetty\fR has some useful features for dial-up lines that are
  70. X/*    not present in the System V Release 2 getty command:
  71. X/* .IP o
  72. X/*    Adapts the tty settings to parity bits and to
  73. X/*    erase, kill and end-of-line characters found in its input. The
  74. X/*    program understands 7-bit characters with even, odd, none or space
  75. X/*    parity, and 8-bit characters with no parity. The following special
  76. X/*    characters are recognized: @ and Control-U (kill); #, DEL and
  77. X/*    back space (erase); carriage return and line feed (end of line).
  78. X/* .IP o
  79. X/*    Optionally recognizes the baud rate of incoming calls from the 
  80. X/*    status messages produced by some multi-speed Hayes-compatible modems.
  81. X/* .IP o
  82. X/*    Optionally does not display the contents of the \fI/etc/issue\fR file.
  83. X/* .PP
  84. X/*    This program does not use the \fI/etc/gettydefs\fR file. Except for 
  85. X/*    differences described in the documentation, the program appears to 
  86. X/*    operate similar to the System-V Release 2 \fIgetty\fR program.
  87. X/*
  88. X/*    Options:
  89. X/* .TP
  90. X/* -a alternate_rates
  91. X/*    Initially the program will use the \fIbaud_rate\fR as specified.
  92. X/*    Upon receipt of successive BREAK characters the program will step
  93. X/*    through the \fIalternate_rates\fR, which should be specified as a
  94. X/*    comma-separated list (preferably in decreasing order). After all
  95. X/*    \fIalternate_rates\fR have been tried, \fIagetty\fR will try the
  96. X/*    speed specified with the \fIbaud_rate\fR argument and so on.
  97. X/* .TP
  98. X/* -h
  99. X/*    Do not hang up the line. Normally, \fIagetty\fR will lower
  100. X/*    DTR for two seconds to force a modem to hang up (if the hangup
  101. X/*    feature has been compiled into the program).
  102. X/* .TP
  103. X/* -i
  104. X/*    Do not display the contents of \fI/etc/issue\fR before writing the 
  105. X/*    login prompt. Terminals or computer programs may become confused
  106. X/*    when receiving lots of text at the wrong baud rate; dial-up scripts
  107. X/*    may fail if the login prompt is preceded by too much text.
  108. X/* .TP
  109. X/* -m
  110. X/*    Try to extract the baud rate of incoming calls from the status message
  111. X/*    produced by some multi-speed Hayes-compatible modems. These usually
  112. X/*    produce a status message of the form: "<junk><speed><junk>".
  113. X/*    If no \fIspeed\fR is found within one second, the \fIbaud_rate\fR as
  114. X/*    specified on the command line will be used. Since the \fI-m\fR feature 
  115. X/*    will work only on lightly-loaded systems, you will probably want to use
  116. X/*    it in combination with the \fI-a\fR option.
  117. X/* .TP
  118. X/* -t timeout
  119. X/*    Causes the program to terminate if no user name could be read
  120. X/*    within \fItimeout\fR seconds. This is useful only for dial-in lines.
  121. X/* EXAMPLES
  122. X/*    For hard-wired lines:
  123. X/* .ti +5
  124. X/*        /etc/agetty ttyM0 9600
  125. X/*
  126. X/*    For dial-in lines with a 300/1200/2400 baud multi-speed modem:
  127. X/* .ti +5
  128. X/*        /etc/agetty -t60 -m -a1200,300 ttyM1 2400
  129. X/* FILES
  130. X/*    /etc/utmp, the system log file.
  131. X/*    /etc/issue, printed before the login prompt.
  132. X/*    /dev/console, problem reports.
  133. X/* BUGS
  134. X/*    The baud-rate detection code (the \fI-m\fR option) only works if
  135. X/*    \fIagetty\fR is scheduled soon enough after completion of a dial-in
  136. X/*    call (within 30 ms with modems that talk at 2400 baud). For robustness,
  137. X/*    always use the \fI-m\fR option in combination with the \fI-a\fR option.
  138. X/*
  139. X/*    The contents of the /etc/issue file and the login prompt are always
  140. X/*    output with space parity.
  141. X/* DIAGNOSTICS
  142. X/*    All diagnostics are written to the console device. Error messages are
  143. X/*    produced if the \fIport\fR argument does not specify a terminal; if 
  144. X/*    there is no /etc/utmp entry for the current process; and so on.
  145. X/* AUTHOR(S)
  146. X/*    W.Z. Venema <wietse@wzv.win.tue.nl>
  147. X/*    Eindhoven University of Technology
  148. X/*    Department of Mathematics and Computer Science
  149. X/*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  150. X/* CREATION DATE
  151. X/*    Sat Nov 25 22:51:05 MET 1989
  152. X/* LAST MODIFICATION
  153. X/*    90/01/28 17:53:06
  154. X/* VERSION/RELEASE
  155. X/*    1.26
  156. X/*--*/
  157. X
  158. X#ifndef lint
  159. Xstatic char sccsid[] = "@(#) agetty.c 1.26 1/28/90 17:53:06";
  160. X#endif
  161. X
  162. X#include <termio.h>
  163. X#include <signal.h>
  164. X#include <sys/types.h>
  165. X#include <sys/stat.h>
  166. X#include <varargs.h>
  167. X#include <ctype.h>
  168. X#include <utmp.h>
  169. X
  170. X /*
  171. X  * Things you may want to modify.
  172. X  * 
  173. X  * HANGUP should be defined only if your tty driver is not able to hang up the
  174. X  * modem (by briefly dropping DTR). If HANGUP is defined you probably cannot
  175. X  * use the auto-baud and time-out features.
  176. X  * 
  177. X  * If ISSUE is not defined, agetty will never display the contents of the
  178. X  * /etc/issue file. You will not want to spit out large "issue" files at the
  179. X  * wrong baud rate.
  180. X  * 
  181. X  * You may disagree with the default line-editing etc. characters defined
  182. X  * below. Note, however, that DEL cannot be used for interrupt generation
  183. X  * and for line editing at the same time.
  184. X  */
  185. X
  186. X#define    ISSUE "/etc/issue"        /* shown before login prompt */
  187. X
  188. X#define LOGIN "login: "            /* login prompt */
  189. X
  190. X/* #define HANGUP            /* enable hangup code */
  191. X
  192. X/* Some shorthands for control characters */
  193. X
  194. X#define CTL(x)        (x ^ 0100)    /* Assumes ASCII dialect */
  195. X#define    CR        CTL('M')    /* carriage return */
  196. X#define    NL        CTL('J')    /* line feed */
  197. X#define    BS        CTL('H')    /* back space */
  198. X#define    DEL        CTL('?')    /* delete */
  199. X
  200. X/* Defaults for line-editing etc. characters; you may want to change this */
  201. X
  202. X#define DEF_INTR    CTL('C')    /* default interrupt character */
  203. X#define DEF_QUIT    CTL('\\')    /* default quit char */
  204. X#define DEF_KILL    CTL('U')    /* default kill char */
  205. X#define DEF_EOF        CTL('D')    /* default EOF char */
  206. X#define DEF_SWITCH    CTL('^')    /* default switch char */
  207. X#define DEF_ERASE    BS        /* default erase char, see below */
  208. X#define DEF_EOL        0
  209. X
  210. X /*
  211. X  * This program does not need the standard-i/o library.  This keeps the
  212. X  * executable small; useful for systems that do not have shared libaries
  213. X  * (Sys-V Rel <3).
  214. X  */
  215. X
  216. X#define    BUFSIZ    1024
  217. X
  218. X/* Storage for command-line options */
  219. X
  220. X#define    MAXSPEED    10
  221. X
  222. Xstruct options {
  223. X    int     flags;            /* toggle switches, see below */
  224. X    int     timeout;            /* time-out period */
  225. X    int     numspeed;            /* number of baud rates to try */
  226. X    int     curspeed;            /* current speed */
  227. X    int     speeds[MAXSPEED];        /* baud rates to be tried */
  228. X    char   *tty;            /* name of tty */
  229. X};
  230. X
  231. X#define    F_PARSE        (1<<0)        /* process modem status messages */
  232. X#define    F_HANGUP    (1<<1)        /* hangup line */
  233. X#define    F_ISSUE        (1<<2)        /* display /etc/issue */
  234. X
  235. X/* Storage for things detected while the login name was read */
  236. X
  237. Xstruct chardata {
  238. X    int     erase;            /* erase character */
  239. X    int     kill;            /* kill character */
  240. X    int     eol;            /* end-of-line character */
  241. X    int     parity;            /* what parity did we see */
  242. X    int     capslock;            /* upper case without lower case */
  243. X};
  244. X
  245. X/* The following is used for understandable diagnostics */
  246. X
  247. Xextern int errno;
  248. Xextern char *sys_errlist[];
  249. Xstatic char *progname;
  250. Xextern char *strcpy();
  251. Xextern char *strcat();
  252. X
  253. X/* ... */
  254. X
  255. Xmain(argc, argv)
  256. Xint     argc;
  257. Xchar  **argv;
  258. X{
  259. X    char   *logname;            /* login name, given to /bin/login */
  260. X    char   *get_logname();
  261. X    struct chardata chardata;        /* set by get_logname() */
  262. X    struct termio termio;        /* terminal mode bits */
  263. X    static struct options options = {
  264. X    F_HANGUP | F_ISSUE,        /* hangup line and show /etc/issue */
  265. X    0,                /* no timeout */
  266. X    1,                /* no alternate baud rates */
  267. X    0,                /* no alternate baud rates */
  268. X    };
  269. X
  270. X    progname = argv[0];
  271. X
  272. X    /* Parse command-line arguments */
  273. X
  274. X    parse_args(argc, argv, &options);
  275. X
  276. X    /* Update the utmp file */
  277. X
  278. X    update_utmp(options.tty);
  279. X
  280. X    /* Open the tty as standard { input, output, error } */
  281. X
  282. X    open_tty(options.tty, &termio);
  283. X
  284. X    /* Optionally hang up the tty */
  285. X
  286. X    if (options.flags & F_HANGUP)
  287. X    hangup_tty(&termio);
  288. X
  289. X    /* Initialize the termio settings (raw mode, eight-bit, blocking i/o) */
  290. X
  291. X    termio_init(&termio, options.speeds[0]);
  292. X
  293. X    /* Optionally detect the baud rate from the modem status message */
  294. X
  295. X    if (options.flags & F_PARSE)
  296. X    auto_baud(&termio);
  297. X
  298. X    /* With dial-in lines, briefly pause to allow modems etc. to settle */
  299. X
  300. X    if (options.timeout)
  301. X    (void) sleep(1);
  302. X
  303. X    /* Optional time-out feature */
  304. X
  305. X    if (options.timeout)
  306. X    (void) alarm((unsigned) options.timeout);
  307. X
  308. X    /* Read the login name */
  309. X
  310. X    while ((logname = get_logname(&options, &chardata, &termio)) == 0)
  311. X    next_speed(&termio, &options);
  312. X
  313. X    /* Disable time-out feature */
  314. X
  315. X    if (options.timeout)
  316. X    (void) alarm(0);
  317. X
  318. X    /* Finalize the termio settings */
  319. X
  320. X    termio_final(&termio, &chardata);
  321. X
  322. X    /* Now the newline character should be properly written */
  323. X
  324. X    (void) write(1, "\n", 1);
  325. X
  326. X    /* Let /bin/login take care of password validation */
  327. X
  328. X    (void) execl("/bin/login", "login", logname, (char *) 0);
  329. X    error("%s: can't exec /bin/login", options.tty);
  330. X    /* NOTREACHED */
  331. X}
  332. X
  333. X/* parse-args - parse command-line arguments */
  334. X
  335. Xparse_args(argc, argv, op)
  336. Xint     argc;
  337. Xchar  **argv;
  338. Xstruct options *op;
  339. X{
  340. X    extern char *optarg;        /* getopt */
  341. X    extern int optind;            /* getopt */
  342. X    int     c;
  343. X
  344. X    while (isascii(c = getopt(argc, argv, "a:himt:"))) {
  345. X    switch (c) {
  346. X    case 'a':                /* enable auto-baud feature */
  347. X        parse_speeds(op, optarg);
  348. X        break;
  349. X    case 'h':                /* do not hangup the tty */
  350. X        op->flags &= ~F_HANGUP;
  351. X        break;
  352. X    case 'i':                /* do not show /etc/issue */
  353. X        op->flags &= ~F_ISSUE;
  354. X        break;
  355. X    case 'm':                /* parse modem status message */
  356. X        op->flags |= F_PARSE;
  357. X        break;
  358. X    case 't':                /* time out */
  359. X        if ((op->timeout = atoi(optarg)) <= 0)
  360. X        error("bad timeout value: %s", optarg);
  361. X        break;
  362. X    case '?':
  363. X        usage();
  364. X    }
  365. X    }
  366. X    if (argc != optind + 2)            /* check parameter count */
  367. X    usage();
  368. X    op->tty = argv[optind++];            /* tty name */
  369. X    if ((op->speeds[0] = bcode(argv[optind])) <= 0)    /* baud rate */
  370. X    error("bad speed: %s", argv[optind]);
  371. X}
  372. X
  373. X/* parse_speeds - parse alternate baud rates */
  374. X
  375. Xparse_speeds(op, arg)
  376. Xstruct options *op;
  377. Xchar   *arg;
  378. X{
  379. X    char   *strtok();
  380. X    char   *cp;
  381. X
  382. X    for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) {
  383. X    if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0)
  384. X        error("bad speed: %s", cp);
  385. X    if (op->numspeed > MAXSPEED)
  386. X        error("too many alternate speeds");
  387. X    }
  388. X}
  389. X
  390. X/* update_utmp - update our utmp entry */
  391. X
  392. Xupdate_utmp(line)
  393. Xchar   *line;
  394. X{
  395. X    struct utmp ut;
  396. X    long    ut_size = sizeof(ut);    /* avoid nonsense */
  397. X    int     ut_fd;
  398. X    int     mypid = getpid();
  399. X    long    time();
  400. X    long    lseek();
  401. X    char   *strncpy();
  402. X
  403. X    /*
  404. X     * The utmp file holds miscellaneous information about things started by
  405. X     * /etc/init and other system-related events. Our purpose is to update
  406. X     * the utmp entry for the current process, in particular the process type
  407. X     * and the tty line we are listening to. Return successfully only if the
  408. X     * utmp file can be opened for update, and if we are able to find our
  409. X     * entry in the utmp file.
  410. X     */
  411. X
  412. X    if ((ut_fd = open(UTMP_FILE, 2)) < 0) {
  413. X    error("%s: open for update", UTMP_FILE);
  414. X    } else {
  415. X    while (read(ut_fd, (char *) &ut, sizeof(ut)) == sizeof(ut)) {
  416. X        if (ut.ut_type == INIT_PROCESS && ut.ut_pid == mypid) {
  417. X        ut.ut_type = LOGIN_PROCESS;
  418. X        ut.ut_time = time((long *) 0);
  419. X        (void) strncpy(ut.ut_name, "LOGIN", sizeof(ut.ut_name));
  420. X        (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line));
  421. X        (void) lseek(ut_fd, -ut_size, 1);
  422. X        (void) write(ut_fd, (char *) &ut, sizeof(ut));
  423. X        (void) close(ut_fd);
  424. X        return;
  425. X        }
  426. X    }
  427. X    error("no utmp entry found for process id %u", mypid);
  428. X    }
  429. X}
  430. X
  431. X/* open_tty - open tty as standard { input, output, error } */
  432. X
  433. Xopen_tty(tty, tp)
  434. Xchar   *tty;
  435. Xstruct termio *tp;
  436. X{
  437. X    struct stat st;
  438. X
  439. X    /* Close standard { input, output, error } files, just in case */
  440. X
  441. X    (void) close(0);
  442. X    (void) close(1);
  443. X    (void) close(2);
  444. X    errno = 0;                    /* ignore above errors */
  445. X
  446. X    /* Make sure we are given a character device */
  447. X
  448. X    if (chdir("/dev"))
  449. X    error("/dev: chdir() failed");
  450. X    if (stat(tty, &st) < 0)
  451. X    error("/dev/%s: stat() failed", tty);
  452. X    if ((st.st_mode & S_IFMT) != S_IFCHR)
  453. X    error("not a character device: /dev/%s", tty);
  454. X
  455. X    /* Set up new standard input, output and error files */
  456. X
  457. X    if (open(tty, 2) != 0)            /* set up std input */
  458. X    error("/dev/%s: cannot open as standard input", tty);
  459. X    if (dup(0) != 1 || dup(0) != 2)        /* set up std out and std err */
  460. X    error("%s: dup problem", tty);        /* we have a problem */
  461. X    if (ioctl(0, TCGETA, tp) < 0)        /* read tty status bits */
  462. X    error("%s: ioctl failed", tty);        /* this is not a terminal */
  463. X
  464. X    /* It seems to be a terminal; set proper protections and ownership */
  465. X
  466. X    (void) chown(tty, 0, 0);            /* root, sys */
  467. X    (void) chmod(tty, 0622);            /* crw--w--w- */
  468. X    errno = 0;                    /* ignore above errors */
  469. X}
  470. X
  471. X#ifdef lint
  472. X#define    HANGUP
  473. X#endif
  474. X
  475. X/* hangup_tty - hang up by forcing DTR down for at least 2 seconds */
  476. X
  477. Xhangup_tty(tp)
  478. Xstruct termio *tp;
  479. X{
  480. X#ifdef    HANGUP
  481. X    (void) signal(SIGHUP, SIG_IGN);
  482. X    tp->c_cflag &= ~CBAUD;
  483. X    tp->c_cflag |= B0;
  484. X    (void) ioctl(0, TCSETA, tp);
  485. X    (void) signal(SIGHUP, SIG_DFL);
  486. X    (void) sleep(2);
  487. X#endif
  488. X}
  489. X
  490. X/* termio_init - initialize termio settings */
  491. X
  492. Xtermio_init(tp, speed)
  493. Xstruct termio *tp;
  494. Xint     speed;
  495. X{
  496. X
  497. X    /*
  498. X     * Initial termio settings: 8-bit characters, raw-mode, blocking i/o.
  499. X     * Special characters are set after we have read the login name; all
  500. X     * reads will be done in raw mode anyway.
  501. X     */
  502. X
  503. X    tp->c_cflag = CS8 | HUPCL | CREAD | speed;
  504. X    tp->c_iflag = tp->c_lflag = tp->c_oflag = tp->c_line = 0;
  505. X    tp->c_cc[VMIN] = 1;
  506. X    tp->c_cc[VTIME] = 0;
  507. X    (void) ioctl(0, TCSETA, tp);
  508. X}
  509. X
  510. X/* auto_baud - extract baud rate from modem status message */
  511. X
  512. Xauto_baud(tp)
  513. Xstruct termio *tp;
  514. X{
  515. X    int     speed;
  516. X    int     vmin;
  517. X    int     iflag;
  518. X    char    buf[BUFSIZ];
  519. X    char   *bp;
  520. X    int     nread;
  521. X
  522. X    /*
  523. X     * This works only if the modem produces its status code AFTER raising
  524. X     * the DCD line, and if the computer is fast enough to set the proper
  525. X     * baud rate before the message has gone by. We expect a message of the
  526. X     * following format:
  527. X     * 
  528. X     * <junk><number><junk>
  529. X     * 
  530. X     * The number is interpreted as the baud rate of the incoming call. If the
  531. X     * modem does not tell us the baud rate within one second we will keep
  532. X     * using the current baud rate. It is advisable to enable baud-rate
  533. X     * cycling (-a option) if the processing of modem status messages is
  534. X     * enabled.
  535. X     */
  536. X
  537. X    /* Use 7-bit characters, don't block if input queue is empty */
  538. X
  539. X    iflag = tp->c_iflag;
  540. X    tp->c_iflag |= ISTRIP;            /* enable 8th-bit stripping */
  541. X    vmin = tp->c_cc[VMIN];
  542. X    tp->c_cc[VMIN] = 0;                /* don't block if queue empty */
  543. X    (void) ioctl(0, TCSETA, tp);
  544. X
  545. X    /*
  546. X     * Wait for a while, then read everything the modem has said so far and
  547. X     * try to extract the speed of the dial-in call.
  548. X     */
  549. X
  550. X    (void) sleep(1);
  551. X    if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) {
  552. X    buf[nread] = '\0';
  553. X    for (bp = buf; bp < buf + nread; bp++) {
  554. X        if (isascii(*bp) && isdigit(*bp)) {
  555. X        if (speed = bcode(bp)) {
  556. X            tp->c_cflag &= ~CBAUD;
  557. X            tp->c_cflag |= speed;
  558. X        }
  559. X        break;
  560. X        }
  561. X    }
  562. X    }
  563. X    /* Restore settings */
  564. X
  565. X    tp->c_iflag = iflag;
  566. X    tp->c_cc[VMIN] = vmin;
  567. X    (void) ioctl(0, TCSETA, tp);
  568. X}
  569. X
  570. X/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
  571. X
  572. Xdo_prompt(op, tp)
  573. Xstruct options *op;
  574. Xstruct termio *tp;
  575. X{
  576. X#ifdef    ISSUE
  577. X    int     fd;
  578. X    int     oflag;
  579. X    int     n;
  580. X    char    buf[BUFSIZ];
  581. X#endif
  582. X
  583. X    write(1, "\r\n", 2);            /* Start a new line */
  584. X#ifdef    ISSUE                    /* Optional: show /etc/issue */
  585. X    if ((op->flags & F_ISSUE) && (fd = open(ISSUE, 0)) >= 0) {
  586. X    oflag = tp->c_oflag;            /* Save current setting */
  587. X    tp->c_oflag |= (ONLCR | OPOST);        /* Map NL in output to CR-NL */
  588. X    (void) ioctl(0, TCSETAW, tp);
  589. X    while ((n = read(fd, buf, sizeof(buf))) > 0)
  590. X        (void) write(1, buf, n);
  591. X    tp->c_oflag = oflag;            /* Restore settings */
  592. X    (void) ioctl(0, TCSETAW, tp);        /* Wait till output gone */
  593. X    (void) close(fd);
  594. X    }
  595. X#endif
  596. X    (void) write(1, LOGIN, sizeof(LOGIN) - 1);    /* Always show login prompt */
  597. X}
  598. X
  599. X/* next_speed - select next baud rate */
  600. X
  601. Xnext_speed(tp, op)
  602. Xstruct termio *tp;
  603. Xstruct options *op;
  604. X{
  605. X    op->curspeed = (op->curspeed + 1) % op->numspeed;
  606. X    tp->c_cflag &= ~CBAUD;
  607. X    tp->c_cflag |= op->speeds[op->curspeed];
  608. X    (void) ioctl(0, TCSETA, tp);
  609. X}
  610. X
  611. X/* get_logname - get user name, establish parity, speed, erase, kill, eol */
  612. X
  613. Xchar   *get_logname(op, cp, tp)
  614. Xstruct options *op;
  615. Xstruct chardata *cp;
  616. Xstruct termio *tp;
  617. X{
  618. X    char    logname[BUFSIZ];
  619. X    char   *bp;
  620. X    char    c;                /* input character, full eight bits */
  621. X    char    ascval;            /* low 7 bits of input character */
  622. X    int     bits;            /* # of "1" bits per character */
  623. X    int     mask;            /* mask with 1 bit up */
  624. X    static char *erase[] = {        /* backspace-space-backspace */
  625. X    "\010\040\010",            /* space parity */
  626. X    "\010\040\010",            /* odd parity */
  627. X    "\210\240\210",            /* even parity */
  628. X    "\210\240\210",            /* no parity */
  629. X    };
  630. X
  631. X    /* Initialize kill, erase, parity etcetera (also after switching speeds) */
  632. X
  633. X    cp->kill = DEF_KILL;
  634. X    cp->erase = DEF_ERASE;
  635. X    cp->parity = 0;
  636. X
  637. X    /* Flush any pending input */
  638. X
  639. X    (void) ioctl(0, TCFLSH, (struct termio *) 0);
  640. X
  641. X    /* Read a login name */
  642. X
  643. X    for (*logname = 0; *logname == 0; /* void */ ) {
  644. X
  645. X    /* Write issue file and prompt, with "parity" bit == 0 */
  646. X
  647. X    do_prompt(op, tp);
  648. X
  649. X    /* Read name, watch for break, parity, erase, kill, end-of-line */
  650. X
  651. X    for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) {
  652. X        if (read(0, &c, 1) < 1)
  653. X        error("%s: read error", op->tty);
  654. X
  655. X        /* Do BREAK handling elsewhere */
  656. X
  657. X        if ((c == 0) && op->numspeed > 1)
  658. X        return (0);
  659. X
  660. X        /* Do parity bit handling */
  661. X
  662. X        if (c != (ascval = (c & 0177))) {    /* "parity" bit on ? */
  663. X        for (bits = 1, mask = 1; mask & 0177; mask <<= 1)
  664. X            if (mask & ascval)
  665. X            bits++;            /* count "1" bits */
  666. X        cp->parity |= ((bits & 1) ? 1 : 2);
  667. X        }
  668. X        /* Do erase, kill and end-of-line processing */
  669. X
  670. X        switch (ascval) {
  671. X        case CR:
  672. X        case NL:
  673. X        *bp = 0;            /* terminate logname */
  674. X        cp->eol = ascval;        /* set end-of-line char */
  675. X        break;
  676. X        case BS:
  677. X        case DEL:
  678. X        case '#':
  679. X        cp->erase = ascval;        /* set erase character */
  680. X        if (bp > logname) {
  681. X            (void) write(1, erase[cp->parity], 3);
  682. X            bp--;
  683. X        }
  684. X        break;
  685. X        case CTL('U'):
  686. X        case '@':
  687. X        cp->kill = ascval;        /* set kill character */
  688. X        while (bp > logname) {
  689. X            (void) write(1, erase[cp->parity], 3);
  690. X            bp--;
  691. X        }
  692. X        break;
  693. X        case CTL('D'):
  694. X        exit(0);
  695. X        default:
  696. X        if (!isascii(ascval) || !isprint(ascval)) {
  697. X             /* ignore garbage characters */ ;
  698. X        } else if (bp - logname >= sizeof(logname) - 1) {
  699. X            error("%s: input overrun", op->tty);
  700. X        } else {
  701. X            (void) write(1, &c, 1);    /* echo the character */
  702. X            *bp++ = ascval;        /* and store it */
  703. X        }
  704. X        break;
  705. X        }
  706. X    }
  707. X    }
  708. X    cp->capslock = caps_lock(logname);        /* upper case w/o lower case? */
  709. X    return (logname);
  710. X}
  711. X
  712. X/* termio_final - set the final tty mode bits */
  713. X
  714. Xtermio_final(tp, cp)
  715. Xstruct termio *tp;
  716. Xstruct chardata *cp;
  717. X{
  718. X    /* General terminal-independent stuff */
  719. X
  720. X    tp->c_iflag |= IXON | IXOFF;        /* 2-way flow control */
  721. X    tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK;
  722. X    tp->c_oflag |= OPOST;
  723. X    tp->c_cc[VEOF] = DEF_EOF;
  724. X    tp->c_cc[VEOL] = DEF_EOL;
  725. X    tp->c_cc[VINTR] = DEF_INTR;
  726. X    tp->c_cc[VQUIT] = DEF_QUIT;
  727. X    tp->c_cc[VKILL] = DEF_KILL;
  728. X    tp->c_cc[VERASE] = DEF_ERASE;
  729. X    tp->c_cc[VSWTCH] = DEF_SWITCH;
  730. X
  731. X    /* Account for special characters seen in input */
  732. X
  733. X    if (cp->eol == CR) {
  734. X    tp->c_iflag |= ICRNL;            /* map CR in input to NL */
  735. X    tp->c_oflag |= ONLCR;            /* map NL in output to CR-NL */
  736. X    }
  737. X    tp->c_cc[VERASE] = cp->erase;        /* set erase character */
  738. X    tp->c_cc[VKILL] = cp->kill;            /* set kill character */
  739. X
  740. X    /* Account for the presence or absence of parity bits in input */
  741. X
  742. X    switch (cp->parity) {
  743. X    case 0:                    /* space (always 0) parity */
  744. X    break;
  745. X    case 1:                    /* odd parity */
  746. X    tp->c_cflag |= PARODD;
  747. X    /* FALLTHROUGH */
  748. X    case 2:                    /* even parity */
  749. X    tp->c_cflag |= PARENB;
  750. X    tp->c_iflag |= INPCK | ISTRIP;
  751. X    /* FALLTHROUGH */
  752. X    case (1 | 2):                /* no parity bit */
  753. X    tp->c_cflag &= ~CSIZE;
  754. X    tp->c_cflag |= CS7;
  755. X    break;
  756. X    }
  757. X    /* Account for upper case without lower case */
  758. X
  759. X    if (cp->capslock) {
  760. X    tp->c_iflag |= IUCLC;
  761. X    tp->c_lflag |= XCASE;
  762. X    tp->c_oflag |= OLCUC;
  763. X    }
  764. X    /* Finally, make the new settings effective */
  765. X
  766. X    (void) ioctl(0, TCSETA, tp);
  767. X}
  768. X
  769. X/* caps_lock - string contains upper case without lower case */
  770. X
  771. Xcaps_lock(s)
  772. Xchar   *s;
  773. X{
  774. X    int     hascaps;
  775. X
  776. X    for (hascaps = 0; *s; s++) {
  777. X    if (islower(*s))
  778. X        return (0);
  779. X    if (hascaps == 0)
  780. X        hascaps = isupper(*s);
  781. X    }
  782. X    return (hascaps);
  783. X}
  784. X
  785. X/* bcode - convert speed string to speed code; return 0 on failure */
  786. X
  787. Xbcode(s)
  788. Xchar   *s;
  789. X{
  790. X    struct Speedtab {
  791. X    int     speed;
  792. X    int     code;
  793. X    };
  794. X    static struct Speedtab speedtab[] = {
  795. X    50, B50,
  796. X    75, B75,
  797. X    110, B110,
  798. X    134, B134,
  799. X    150, B150,
  800. X    200, B200,
  801. X    300, B300,
  802. X    600, B600,
  803. X    1200, B1200,
  804. X    1800, B1800,
  805. X    2400, B2400,
  806. X    4800, B4800,
  807. X    9600, B9600,
  808. X    19200, EXTA,
  809. X    0, 0,
  810. X    };
  811. X    struct Speedtab *sp;
  812. X    int     speed = atoi(s);
  813. X
  814. X    for (sp = speedtab; sp->speed; sp++)
  815. X    if (sp->speed == speed)
  816. X        return (sp->code);
  817. X    return (0);
  818. X}
  819. X
  820. X/* usage - explain */
  821. X
  822. Xusage()
  823. X{
  824. X    static char args[] =
  825. X    "[-a alternate_rates] [-h] [-i] [-m] [-t timeout] line baud_rate";
  826. X
  827. X    error("usage: %s %s", progname, args);
  828. X}
  829. X
  830. X/* error - report errors to the console; only understands %s */
  831. X
  832. X#define    str2cpy(b,s1,s2)    strcat(strcpy(b,s1),s2)
  833. X
  834. X/* VARARGS */
  835. X
  836. Xerror(va_alist)
  837. Xva_dcl
  838. X{
  839. X    va_list ap;
  840. X    char   *fmt;
  841. X    int     fd;
  842. X    int     err = errno;
  843. X    char    buf[BUFSIZ];
  844. X    char   *bp;
  845. X
  846. X    if ((fd = open("/dev/console", 1)) >= 0) {
  847. X    (void) str2cpy(buf, progname, ": ");
  848. X    bp = buf + strlen(buf);
  849. X
  850. X    /*
  851. X     * %s expansion is done by hand. The program would become three times
  852. X     * as big if we would use the stdio library...
  853. X     */
  854. X
  855. X    va_start(ap);
  856. X    fmt = va_arg(ap, char *);
  857. X    while (*fmt) {
  858. X        if (strncmp(fmt, "%s", 2) == 0) {
  859. X        (void) strcat(bp, va_arg(ap, char *));
  860. X        bp += strlen(bp);
  861. X        fmt += 2;
  862. X        } else {
  863. X        *bp++ = *fmt++;
  864. X        }
  865. X    }
  866. X    *bp = 0;
  867. X    va_end(ap);
  868. X
  869. X    /* Add system error message if errno was set */
  870. X
  871. X    if (err)
  872. X        (void) str2cpy(bp, ": ", sys_errlist[errno]);
  873. X
  874. X    /* Terminate with CR-LF since the console mode is unknown */
  875. X
  876. X    (void) strcat(bp, "\r\n");
  877. X    (void) write(fd, buf, strlen(buf));
  878. X    (void) close(fd);
  879. X    }
  880. X    (void) sleep(5);                /* be kind to init */
  881. X    exit(1);
  882. X}
  883. END_OF_FILE
  884. if test 22691 -ne `wc -c <'agetty.c'`; then
  885.     echo shar: \"'agetty.c'\" unpacked with wrong size!
  886. fi
  887. # end of 'agetty.c'
  888. fi
  889. if test -f 'agetty.8' -a "${1}" != "-c" ; then 
  890.   echo shar: Will not clobber existing file \"'agetty.8'\"
  891. else
  892. echo shar: Extracting \"'agetty.8'\" \(3984 characters\)
  893. sed "s/^X//" >'agetty.8' <<'END_OF_FILE'
  894. X.TH AGETTY 8 
  895. X.ad
  896. X.fi
  897. X.SH NAME
  898. Xagetty
  899. X\-
  900. Xalternative System-V getty for dial-up lines
  901. X.SH SYNOPSIS
  902. X.na
  903. X.nf
  904. Xagetty [-a alternate_rates] [-h] [-i] [-m] [-t timeout] port baud_rate
  905. X.SH DESCRIPTION
  906. X.ad
  907. X.fi
  908. X\fIagetty\fR opens a tty port, prompts for a login name and invokes the
  909. X/bin/login command. It is normally invoked by \fIinit(8)\fR.
  910. X
  911. X\fIagetty\fR has some useful features for dial-up lines that are
  912. Xnot present in the System V Release 2 getty command:
  913. X.IP o
  914. XAdapts the tty settings to parity bits and to
  915. Xerase, kill and end-of-line characters found in its input. The
  916. Xprogram understands 7-bit characters with even, odd, none or space
  917. Xparity, and 8-bit characters with no parity. The following special
  918. Xcharacters are recognized: @ and Control-U (kill); #, DEL and
  919. Xback space (erase); carriage return and line feed (end of line).
  920. X.IP o
  921. XOptionally recognizes the baud rate of incoming calls from the
  922. Xstatus messages produced by some multi-speed Hayes-compatible modems.
  923. X.IP o
  924. XOptionally does not display the contents of the \fI/etc/issue\fR file.
  925. X.PP
  926. XThis program does not use the \fI/etc/gettydefs\fR file. Except for
  927. Xdifferences described in the documentation, the program appears to
  928. Xoperate similar to the System-V Release 2 \fIgetty\fR program.
  929. X
  930. XOptions:
  931. X.TP
  932. X-a alternate_rates
  933. XInitially the program will use the \fIbaud_rate\fR as specified.
  934. XUpon receipt of successive BREAK characters the program will step
  935. Xthrough the \fIalternate_rates\fR, which should be specified as a
  936. Xcomma-separated list (preferably in decreasing order). After all
  937. X\fIalternate_rates\fR have been tried, \fIagetty\fR will try the
  938. Xspeed specified with the \fIbaud_rate\fR argument and so on.
  939. X.TP
  940. X-h
  941. XDo not hang up the line. Normally, \fIagetty\fR will lower
  942. XDTR for two seconds to force a modem to hang up (if the hangup
  943. Xfeature has been compiled into the program).
  944. X.TP
  945. X-i
  946. XDo not display the contents of \fI/etc/issue\fR before writing the
  947. Xlogin prompt. Terminals or computer programs may become confused
  948. Xwhen receiving lots of text at the wrong baud rate; dial-up scripts
  949. Xmay fail if the login prompt is preceded by too much text.
  950. X.TP
  951. X-m
  952. XTry to extract the baud rate of incoming calls from the status message
  953. Xproduced by some multi-speed Hayes-compatible modems. These usually
  954. Xproduce a status message of the form: "<junk><speed><junk>".
  955. XIf no \fIspeed\fR is found within one second, the \fIbaud_rate\fR as
  956. Xspecified on the command line will be used. Since the \fI-m\fR feature
  957. Xwill work only on lightly-loaded systems, you will probably want to use
  958. Xit in combination with the \fI-a\fR option.
  959. X.TP
  960. X-t timeout
  961. XCauses the program to terminate if no user name could be read
  962. Xwithin \fItimeout\fR seconds. This is useful only for dial-in lines.
  963. X.SH EXAMPLES
  964. X.na
  965. X.nf
  966. XFor hard-wired lines:
  967. X.ti +5
  968. X/etc/agetty ttyM0 9600
  969. X
  970. XFor dial-in lines with a 300/1200/2400 baud multi-speed modem:
  971. X.ti +5
  972. X/etc/agetty -t60 -m -a1200,300 ttyM1 2400
  973. X.SH FILES
  974. X.na
  975. X.nf
  976. X/etc/utmp, the system log file.
  977. X/etc/issue, printed before the login prompt.
  978. X/dev/console, problem reports.
  979. X.SH BUGS
  980. X.ad
  981. X.fi
  982. XThe baud-rate detection code (the \fI-m\fR option) only works if
  983. X\fIagetty\fR is scheduled soon enough after completion of a dial-in
  984. Xcall (within 30 ms with modems that talk at 2400 baud). For robustness,
  985. Xalways use the \fI-m\fR option in combination with the \fI-a\fR option.
  986. X
  987. XThe contents of the /etc/issue file and the login prompt are always
  988. Xoutput with space parity.
  989. X.SH DIAGNOSTICS
  990. X.ad
  991. X.fi
  992. XAll diagnostics are written to the console device. Error messages are
  993. Xproduced if the \fIport\fR argument does not specify a terminal; if
  994. Xthere is no /etc/utmp entry for the current process; and so on.
  995. X.SH AUTHOR(S)
  996. X.na
  997. X.nf
  998. XW.Z. Venema <wietse@wzv.win.tue.nl>
  999. XEindhoven University of Technology
  1000. XDepartment of Mathematics and Computer Science
  1001. XDen Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1002. X.SH CREATION DATE
  1003. X.na
  1004. X.nf
  1005. XSat Nov 25 22:51:05 MET 1989
  1006. X.SH LAST MODIFICATION
  1007. X.na
  1008. X.nf
  1009. X90/01/28 17:53:06
  1010. X.SH VERSION/RELEASE
  1011. X.na
  1012. X.nf
  1013. X1.26
  1014. END_OF_FILE
  1015. if test 3984 -ne `wc -c <'agetty.8'`; then
  1016.     echo shar: \"'agetty.8'\" unpacked with wrong size!
  1017. fi
  1018. # end of 'agetty.8'
  1019. fi
  1020. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  1021.   echo shar: Will not clobber existing file \"'Makefile'\"
  1022. else
  1023. echo shar: Extracting \"'Makefile'\" \(257 characters\)
  1024. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  1025. X# @(#) Makefile 1.3 11/26/89 22:20:28 
  1026. X
  1027. XSHELL    = /bin/sh
  1028. XCFLAGS    = -s -O
  1029. XFILES    = README agetty.c agetty.8 Makefile
  1030. X
  1031. Xagetty: agetty.c
  1032. X    cc $(CFLAGS) -o $@ $?
  1033. X
  1034. Xclean:
  1035. X    rm -f agetty.o agetty
  1036. X
  1037. Xshar:    $(FILES)
  1038. X    @shar $(FILES)
  1039. X
  1040. Xagetty.8:
  1041. X    srctoman agetty.c >agetty.8
  1042. END_OF_FILE
  1043. if test 257 -ne `wc -c <'Makefile'`; then
  1044.     echo shar: \"'Makefile'\" unpacked with wrong size!
  1045. fi
  1046. # end of 'Makefile'
  1047. fi
  1048. echo shar: End of shell archive.
  1049. exit 0
  1050.  
  1051.